package playgame;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * A soundplayer that plays wave-files loaded from file
 * 
 * @author Bomberman Crew 20(C)09
 *
 */

public class SoundPlayer implements Runnable {
	
	private boolean running;
	SourceDataLine line;
	
	public void run() {
		running = true;
		while(running){
			try {
				playSound();
				Thread.sleep(0);
			}
			catch (InterruptedException e) {
				// DO NOTHING
			}
		}
		
	}
	
	public void stop(){
		running = false;
	}

	private AudioFormat format;
	 private byte[] samples;
	 private String filename;

	/**
	 * Opens a sound from a file
	 * @param filename
	 * takes a String as a parameter
	 */
	public SoundPlayer(String filename){
		this.filename = "sounds/" + filename + ".wav";
		try{
			// open the audio input stream
			AudioInputStream ais = AudioSystem.getAudioInputStream(new File(this.filename));
			format = ais.getFormat();
			
			//get the audio samples
			samples = getSamples(ais);
		}
		catch(UnsupportedAudioFileException ex){
			ex.printStackTrace();
		}
		catch(IOException ex){
			ex.printStackTrace();
		}
//		Thread t = new Thread(this);
//		t.run();
	}
	/**
	 * returns the samples of THIS sound as a byte-array
	 * @return
	 */
	public byte[] getSamples(){
		return samples;
	}
	/**
	 * byte array method which takes an audio input stream
	 * and returns a byte array loaded with bytes
	 * @param stream
	 * @return
	 */
	private byte[] getSamples(AudioInputStream stream){
		
		//gets the number of bytes to read
		int length = (int) (stream.getFrameLength()*format.getFrameSize());
		
		// reads the entire stream
		byte[] samples = new byte[length];
		DataInputStream is = new DataInputStream(stream);
		try{
			is.readFully(samples);
		}
		catch(IOException ex){
			ex.printStackTrace();
		}
		
		//returns the samples
		return samples;
	}
	
	/**
	 * plays a stream. returns when the sounds are finished playing
	 * @param source
	 * takes an InputStream as a parameter
	 */
	public void play(InputStream source){
		
		//uses a short buffer for real-time change to the sound stream
		int buffersize = format.getFrameSize() * Math.round(format.getSampleRate()/10);
		byte[] buffer = new byte[buffersize];
		
		//creates a line to play to
		
		try{
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
			line = (SourceDataLine)AudioSystem.getLine(info);
			line.open(format, buffersize);
		}
		catch(LineUnavailableException ex){
			ex.printStackTrace();
			return;
		}
		
		//starts the line
		line.start();
		
		//copies data to the line
		try{
			int numBytesRead = 0;
			while(numBytesRead != -1){
				numBytesRead = source.read(buffer,0,buffer.length);
				if(numBytesRead != -1){
					line.write(buffer, 0, numBytesRead);
				}
			}
		}
		catch(IOException ex){
			ex.printStackTrace();
		}
		
		//waits until all the data is played, and then closes the line
		line.drain();
		line.close();
	}
	
	public void stopSound(){
		line.flush();
		line.stop();
		line.close();
	}
	
	/**
	 * plays the sound which is sent to the constructor
	 * 
	 */
	public void playSound(){
		//SoundPlayer test = new SoundPlayer(this.filename);
		InputStream stream = new ByteArrayInputStream(this.getSamples());
		this.play(stream);
	}
	
	
}
